/* $Header: err_handler.c,v 2.2 01/10/02 10:26:55 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991, 1992           */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME:  err_hander.c                                          */
/* ============                                                        */
/*                                                                     */
/* Author:  Lesley Freed                                               */
/*                                                                     */
/* MODULE PURPOSE:  To process any non-fatal errrors or warnings       */
/*                  found for display and I/O output.                  */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/

#include <typedefs.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <p_status.h>
#include <zone_status.h>
#include <status.h>
#include <error.h>
#include <i_op.h>
#include <messages.h>
#include <beep.h>
#include <display.h>

#include <exception.h>
#include <err_handler.h>
#include <glp.h>

#include <p_ui.h>

/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/

        EXCEPTION_DISPLAY Exception_Display;

/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/


/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

/*****************************/
/*   STATIC VARIABLES        */
/*****************************/


/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/

BIT8 TestForStatusDisplayWarning ( void );

#pragma SECTION PROG=SysCode

void SetNewException( EXCEPTION flag, INT32 param1, INT32 param2 )
{
   EXCEPTION_WORDS *words;
   BIT32           mask;

   words  = Exception_Info[ flag ].words;
   mask   = Exception_Info[ flag ].bit_mask;


   if (( flag >= (EXCEPTION) 0 ) && ( flag < LAST_EXCEPTION_NAME ))
   {

        INTERRUPTS_OFF

        if (( Exception_Info[flag].repeatable ) ||
            (( words->status & mask ) == 0 ) )
        {
            /* Set The Exception */
            words->status |= mask;

            /* Flag That it has been re-evaluated */
            if ( Ramps_Executed ) words->eval   |= mask;

            /* handle the pop up message if this exception is a higher value */
            /* any exception pop ups that are currently being displayed.     */

            if (( Exception_Info[ flag  ].msg_no != NO_MSG ) &&
                ( Exception_Display.type < (EXCEPTION_TYPE)Exception_Info[flag].exception_type))
            {

                 Exception_Display.type   = (EXCEPTION_TYPE)Exception_Info[flag].exception_type;
                 Exception_Display.msg_no = Exception_Info[flag].msg_no;
                 Exception_Display.exception_no = (EXCEPTION)Exception_Info[flag].exception_no;
                 Exception_Display.param[0]     = param1;
                 Exception_Display.param[1]     = param2;

                 Exception_Display.request      = TRUE;
            }

        }

        /* if this event has not been logged for glp, log it */

        if (( Exception_Info[ flag ].glp_msg_no != NO_MSG ) &&
            ( (words->glp & mask) == 0 ))
        {
           words->glp |= mask;

           LogException( flag, param1, param2 );
        }

        INTERRUPTS_ON
    }
}

void ClearNewException( EXCEPTION flag )
{
   EXCEPTION_WORDS *words;
   U_INT32 mask;

   words   = Exception_Info[ flag ].words;
   mask    = Exception_Info[ flag ].bit_mask;

   if (( flag >= (EXCEPTION) 0 ) && ( flag < LAST_EXCEPTION_NAME ))
   {

        INTERRUPTS_OFF

        /* Clear The Exception */
        words->status &= ~mask;

        /* Flag That it has been re-evaluated */
        if ( Ramps_Executed ) words->eval   |= mask;

        /* let glp know the deviation has ended */
        words->glp &= ~mask;

        INTERRUPTS_ON
    }
}

#pragma SECTION UNDO

 /**********************************************************************

    E x c e p t i o n   B a s e d   F u n c t i o n s

  **********************************************************************/

BIT8 TestForException( EXCEPTION flag )
{
   EXCEPTION_WORDS  *words;
   BIT32            mask;
   BIT32            result;

   words  = Exception_Info[ flag ].words;
   mask   = Exception_Info[ flag ].bit_mask;
   result = 0;

   if (( flag >= (EXCEPTION) 0 ) && ( flag < LAST_EXCEPTION_NAME ))
   {
        result = words->status & mask;
   }

   if ( result == 0 ) return FALSE;

   return TRUE;

}

static U_INT16 GetExceptionType( EXCEPTION flag )
{
   return Exception_Info[ flag ].exception_type;

}

BIT8 ValidExceptionIndex( EXCEPTION type )
{
   BIT8    result;

   result = FALSE;

   if (( type >= (EXCEPTION) 0 ) && ( type < LAST_EXCEPTION_NAME ))
   {
        result = TRUE;
   }

   return result;
}



/***********************************************************************/
/* FUNCTION:  ActiveStatusTitle                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: To determine if a status line title should be displayed.   */
/*                                                                     */
/* RETURNED VALUE: BIT16:  TRUE = 1, FALSE = 0                         */
/*                                                                     */
/* GLOBALS USED:  Exception_Info                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

BIT8 ActiveStatusTitle( EXCEPTION flag )
{
   if ( GetExceptionType( flag ) == (U_INT16)SCROLLING_TITLE )
   {
      /* See if we should display the title */
      switch( Exception_Info[ flag ].glp_dev_code )
      {
         case WARNING_CLASS:        return TestForStatusDisplayWarning();
         case METHOD_WARNING_CLASS: return TestForMethodWarning();
         case NON_FATAL_ERR_CLASS:  return TestForNonFatalErr();
      }
   }
   return FALSE;
}


#pragma SECTION PROG=SysCode

/***********************************************************************/
/* FUNCTION:  Old SetException                                         */
/* ========                                                            */
/*                                                                     */
/***********************************************************************/


void SetException( EXCEPTION flag )
{

   SetNewException( flag, 0, 0 );

}


/***********************************************************************/
/* FUNCTION:  Old ClearException                                       */
/* ========                                                            */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

void ClearException( EXCEPTION flag )
{

   ClearNewException( flag );

}

#pragma SECTION UNDO


/***********************************************************************/
/* FUNCTION:   CheckForExceptionDisplay                                */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To display a pending request for an exception display     */
/*           on the GC display.  The exception will be displayed only  */
/*           if it is of a higher priority than the active display.    */
/*           The act of hitting a key will clear the exception display */
/*           an set the exception display to lowest priority, thereby  */
/*           enabling any subsequent exception display.                */
/*                                                                     */
/* RETURNED VALUE:  none                                               */
/*                                                                     */
/* GLOBALS USED:  Exception_Display                                    */
/*                                                                     */
/* CALLS:  DisplayWarnings, DisplayShutdowns, DisplayNonFatalErrs      */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void CheckForExceptionDisplay( void )
{
   if ( Exception_Display.request == TRUE )
   {
      switch( Exception_Display.type )
      {
         case METHOD_WARNING_0:
         case WARNING_0:
         case WARNING_1:
              DisplayWarnings( Exception_Display.msg_no,
                               Exception_Display.exception_no,
                               Exception_Display.param[0],
                               Exception_Display.param[1] );
              if (GetWarningBeepEnabled())
              {
                 BEEP_WARNING
              }
              Exception_Display.request = FALSE;
              break;

         case SHUTDOWN_0:
              DisplayShutdowns( Exception_Display.msg_no,
                                Exception_Display.exception_no,
                                Exception_Display.param[0],
                                Exception_Display.param[1] );
              if (GetWarningBeepEnabled())
              {
                 BEEP_WARNING
              }
              Exception_Display.request = FALSE;
              break;

         case NON_FATAL_ERR_0:
              DisplayNonFatalErrors( Exception_Display.msg_no,
                                     Exception_Display.exception_no,
                                     Exception_Display.param[0],
                                     Exception_Display.param[1] );
              Exception_Display.request = FALSE;
              break;

         case NON_FATAL_ERR_1:
              DisplayNonFatalErrors( Exception_Display.msg_no,
                                     Exception_Display.exception_no,
                                     Exception_Display.param[0],
                                     Exception_Display.param[1] );
              BEEP_WARNING
              Exception_Display.request = FALSE;
              break;

         case NON_FATAL_ERR_2:
              DisplayNonFatalErrors( Exception_Display.msg_no,
                                     Exception_Display.exception_no,
                                     Exception_Display.param[0],
                                     Exception_Display.param[1] );
              BEEP_NON_FATAL_ERR
              Exception_Display.request = FALSE;
              break;

         case POWER_ON_DISPLAY:
              /* Note:  We will do NOTHING in this case.  We will */
              /* keep the exception display locked so that the    */
              /* power on message remains until someone has hit   */
              /* the first key on the keyboard.                   */
              break;
         default:
              Exception_Display.request = FALSE;
      }
   }

}


/******************/
/* Test Functions */
/******************/

/* TestForNotReadyPreRun will exclude the not ready conditions that require */
/* the pre-run state to be made ready.  This function will allow state      */
/* machines to hold off on going into pre-run until the rest of the instru- */
/* ment is ready.                                                           */

BIT8 TestForNotReadyPreRun ( void )
{
   U_INT32 mask;

   /* First create a mask that excludes the pre-run NR's */
   /* WARNING:  This depends upon the pre-run NR's being */
   /*           in the first Not_Ready exception word    */

   mask = NOT_READY_VALID_BITS[0] &
          ~Exception_Info[ MISER_MODE ].bit_mask &
          ~Exception_Info[ FRNT_INLET_VI_FLOW   ].bit_mask &
          ~Exception_Info[ BACK_INLET_VI_FLOW   ].bit_mask &
          ~Exception_Info[ FRNT_INLET_SOLV_VENT ].bit_mask &
          ~Exception_Info[ BACK_INLET_SOLV_VENT ].bit_mask &
          ~Exception_Info[ FRNT_INLET_PURGING   ].bit_mask &
          ~Exception_Info[ BACK_INLET_PURGING   ].bit_mask &
          ~Exception_Info[ FRNT_INLET_PULSE     ].bit_mask &
          ~Exception_Info[ BACK_INLET_PULSE     ].bit_mask;

   if ( Not_Ready[0].status & mask )
   {
      return TRUE;
   }
   else
   {
      return FALSE;
   }
}

/***********************************************************************/
/* FUNCTION:  TestForExceptionClass                                    */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To test for the presence of an exception of a particular  */
/*           class.                                                    */
/*                                                                     */
/* RETURNED VALUE:  TRUE:  one or more exceptions active               */
/*                  FALSE: no exception active                         */
/*                                                                     */
/* CALLS:  none                                                        */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

static BIT8 TestForExceptionClass( const EXCEPTION_CLASS_INFO *info )
{
   EXCEPTION_WORDS *words;
   INT16 i;
   BIT32 result;

   words  = info->words;
   result = 0;

   for ( i = 0; i < info->word_count; i++ )
   {
      result |= words->status;
      words++;
   }

   if ( result )
   {
      return TRUE;
   }
   else
   {
      return FALSE;
   }
}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE: TRUE = evaluated, FALSE = not evaluated             */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

static BIT8 TestForExceptionClassEval( const EXCEPTION_CLASS_INFO *info )
{
   INT16           i;
   EXCEPTION_WORDS *words;
   const BIT32     *valid_bits;
   BIT32           mask,result,eval_bits;

   words      = info->words;
   valid_bits = info->valid_bits;
   result = 0;

   for ( i = 0; i < info->word_count; i++ )
   {
      /* get the mask and the eval bits */
      mask      = *valid_bits;
      eval_bits = words->eval;

      /* now check to see if all those bits have been evaluated */
      result |= (eval_bits ^ mask);

      words++;
      valid_bits++;
   }

   if ( result )
   {
      return FALSE;
   }
   else
   {
      return TRUE;
   }
}

void SetEvalReadyBit( EXCEPTION flag )
{
   Exception_Info[ flag ].words->eval |= Exception_Info[ flag ].bit_mask;
}

/***********************************************************************/
/* FUNCTION:   TestForNotReadyCore                                     */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To test for readiness of the Not_Ready_Core word(s)       */
/*                                                                     */
/* RETURNED VALUE:  TRUE = not ready, FALSE = ready                    */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

BIT8 TestForNotReadyCore( void )
{
   return TestForExceptionClass( &NOT_READY_CORE_INFO );
}


/***********************************************************************/
/* FUNCTION:   TestForNotReadyCoreEval                                 */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To test for evaluation of the Not_Ready_Core word(s)      */
/*                                                                     */
/* RETURNED VALUE:  TRUE = evaluated, FALSE = not evaluated            */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

BIT8 TestForNotReadyCoreEval( void )
{
   return TestForExceptionClassEval( &NOT_READY_CORE_INFO );
}

BIT8 TestForNotReady( void )
{
   return TestForExceptionClass( &NOT_READY_INFO );
}

BIT8 TestForNotReadyEval( void )
{
   return TestForExceptionClassEval( &NOT_READY_INFO );
}

BIT8 TestForNotReadyDet( void )
{
   return TestForExceptionClass( &NOT_READY_DET_INFO );
}

BIT8 TestForNotReadyDetEval( void )
{
   return TestForExceptionClassEval( &NOT_READY_DET_INFO );
}


#if 0
BIT8 TestForWarning ( void )
{
   return TestForExceptionClass( &WARNING_INFO );
}
#else
BIT8 TestForWarning ( void )
{
   return TestForStatusDisplayWarning();
}
#endif

BIT8 TestForStatusDisplayWarning ( void )
{
   U_INT32 mask;
   INT16 i;
   BIT32 result;

   mask = ~Exception_Info[ GLP_OVERFLOW ].bit_mask;
   result = GetWarning(1) & mask;
   if ( result )
   {
      return TRUE;
   }

   mask = ~Exception_Info[ COL1_PNEU_TIME1_CONFLICT ].bit_mask &
          ~Exception_Info[ COL2_PNEU_TIME1_CONFLICT ].bit_mask &
          ~Exception_Info[ FINL_PNEU_TIME1_CONFLICT ].bit_mask &
          ~Exception_Info[ BINL_PNEU_TIME1_CONFLICT ].bit_mask &
          ~Exception_Info[ FINL_PURG_TIME_CONFLICT ].bit_mask &
          ~Exception_Info[ BINL_PURG_TIME_CONFLICT ].bit_mask &
          ~Exception_Info[ MEMORY_RESET ].bit_mask &
          ~Exception_Info[ OEM_DET_CFG_CHGD ].bit_mask;
   result = GetWarning(2) & mask;
   if ( result )
   {
      return TRUE;
   }

   for ( i = 3; i <= WARNING_INFO.word_count; i++ )
   {
      result = GetWarning(i);
      if ( result )
      {
         return TRUE;
      }
   }

   return FALSE;
}

BIT8 TestForShutdown ( void )
{
   return TestForExceptionClass( &SHUTDOWN_INFO );
}

BIT8 TestForNonFatalErr ( void )
{
   return TestForExceptionClass( &NON_FATAL_ERR_INFO );
}
BIT8 TestForMethodWarning ( void )
{
   return TestForExceptionClass( &METHOD_WARNING_INFO );
}


/*****************/
/* Get Functions */
/*****************/

/* The following function returns one of the internal not     */
/* ready status words.  1:  the core (all the pneumatics and  */
/* small zone control readiness) 2: the det control readiness */
/* or 3:  the rest of the instrument's readiness.             */

INT32 GetNotReady( INT16 word )
{
   switch( word )
   {
      case 1: return Not_Ready_Core[0].status;
      case 2: return Not_Ready_Det[0].status;
      default:
      case 3: return Not_Ready[0].status;
   }
}

INT32 GetNotReadyExt( void )
{
   return Not_Ready_Ext[0].status;
}

INT32 GetWarning( INT16 word )
{
   /* Check for out of bounds warning */
   if ( word > WARNING_WORD_COUNT )
   {
      return 0;
   }

   return Warning[word-1].status;
}

INT32 GetMethodWarning( INT16 word )
{
   /* Check for out of bounds warning */
   if ( word > METHOD_WARNING_WORD_COUNT )
   {
      return 0;
   }

   return Method_Warning[word-1].status;
}

INT32 GetShutdown( INT16 word )
{
   /* Check for out of bounds warning */
   if ( word > SHUTDOWN_WORD_COUNT )
   {
      return 0;
   }

   return Shutdown[word-1].status;
}

INT32 GetNonFatalErr( INT16 word )
{
   /* Check for out of bounds warning */
   if ( word > NON_FATAL_ERR_WORD_COUNT )
   {
      return 0;
   }

   return Non_Fatal_Err[word-1].status;
}


/***********************************************************************/
/* FUNCTION:  HoldOffTestForNotReadyCore                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To test for the presence of an exception of a particular  */
/*           class.                                                    */
/*                                                                     */
/*     this routine is special to avoid deadlocks when powering        */
/*     on in recovery mode.  we could have a case where the flow       */
/*     system is in const pres mode, such that a now cool oven         */
/*     has caused a flow sensor to cap.  This should NOT keep          */
/*     the oven in hold off.  I know this is ugly, but there does      */
/*     not seem to be a better way.                                    */
/*                                                                     */
/*                                                                     */
/* RETURNED VALUE:  TRUE:  one or more exceptions active               */
/*                  FALSE: no exception active                         */
/*                                                                     */
/* CALLS:  none                                                        */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

BIT8 HoldOffTestForNotReadyCore( void )
{
   EXCEPTION_WORDS *words;
   INT16 i;
   BIT32 result;
   BIT32 temp;

   words  = NOT_READY_CORE_INFO.words;
   result = 0;

   for ( i = 0; i < NOT_READY_CORE_INFO.word_count; i++ )
   {
      temp = words->status;

      if (( words == (EXCEPTION_WORDS *)Exception_Info[ FRNT_INLET_FLOW  ].words ) &&
          ( OkToReleaseOvenHoldOff( pFRONT_INLET ) ))
      {
           temp &= ~Exception_Info[ FRNT_INLET_FLOW ].bit_mask;
      }

      if (( words == (EXCEPTION_WORDS *)Exception_Info[ BACK_INLET_FLOW  ].words ) &&
          ( OkToReleaseOvenHoldOff( pBACK_INLET ) ))
      {
           temp &= ~Exception_Info[ BACK_INLET_FLOW ].bit_mask;
      }


      result |= temp;
      words++;
   }

   if ( result )
   {
      return TRUE;
   }
   else
   {
      return FALSE;
   }
}


/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*     this routine is special to avoid deadlocks when powering        */
/*     on in recovery mode.  we could have a case where the flow       */
/*     system is in const pres mode, such that a now cool oven         */
/*     has caused a flow sensor to cap.  This should NOT keep          */
/*     the oven in hold off.  I know this is ugly, but there does      */
/*     not seem to be a better way.                                    */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/* RETURNED VALUE: TRUE = evaluated, FALSE = not evaluated             */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

BIT8 HoldOffTestForNotReadyCoreEval( void )
{
   INT16           i;
   EXCEPTION_WORDS *words;
   const BIT32     *valid_bits;
   BIT32           mask,result,eval_bits;

   words      = NOT_READY_CORE_INFO.words;
   valid_bits = NOT_READY_CORE_INFO.valid_bits;
   result = 0;

   for ( i = 0; i < NOT_READY_CORE_INFO.word_count; i++ )
   {
      /* get the mask and the eval bits */
      mask      = *valid_bits;
      eval_bits = words->eval;

      if (( words == (EXCEPTION_WORDS *)Exception_Info[ FRNT_INLET_FLOW  ].words ) &&
          ( OkToReleaseOvenHoldOff( pFRONT_INLET ) ))
      {
           /* nullify this bit in the subsequent xor operation */
           mask      |=  Exception_Info[ FRNT_INLET_FLOW ].bit_mask;
           eval_bits |=  Exception_Info[ FRNT_INLET_FLOW ].bit_mask;
      }

      if (( words == (EXCEPTION_WORDS *)Exception_Info[ BACK_INLET_FLOW  ].words ) &&
          ( OkToReleaseOvenHoldOff( pBACK_INLET ) ))
      {
           /* nullify this bit in the subsequent xor operation */
           mask      |=  Exception_Info[ BACK_INLET_FLOW ].bit_mask;
           eval_bits |=  Exception_Info[ BACK_INLET_FLOW ].bit_mask;
      }

      /* now check to see if all those bits have been evaluated */
      result |= (eval_bits ^ mask);

      words++;
      valid_bits++;
   }

   if ( result )
   {
      return FALSE;
   }
   else
   {
      return TRUE;
   }
}

